package com.hibase.core.page.utils;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.StringUtils;

import com.github.pagehelper.util.StringUtil;
import com.hibase.common.entity.fileutlis.FileUtilsVo;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: FileUtils
 * @Description: TODO
 * @author: TimBrian
 * @date: 2021年11月5日 下午5:05:16
 */
@Slf4j
public class FileUtils {
	
	/**
	 * file downloadSize
	 */
	public static final Integer BUFF_SIZE = 2048;

	private static ZipOutputStream zipOutputStream = null;
	private static FileInputStream fileInputStream = null;

	/**
	 * 
	 * @Title: FileUtils
	 * @Description: 文件批量下载
	 * @author TimBrian
	 * @since 2018年11月5日 下午5:14:12
	 * @param response
	 * @param filePath
	 * @param request
	 * @param reportName
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static boolean zipDownload(HttpServletRequest request, HttpServletResponse response, File[] filePath, 
			String reportName) throws FileNotFoundException, IOException {
		// 响应头的设置
		response.reset();
		response.setCharacterEncoding("utf-8");
		response.setContentType("multipart/form-data");
		// 设置压缩包的名字
		// 解决不同浏览器压缩包名字含有中文时乱码的问题
		String downloadName = reportName + ".zip";
		// 设置文件保存路径和文件名

		// 返回客户端浏览器的版本号、类型
		String agent = request.getHeader("USER-AGENT");
		// 针对IE或者以IE为内核的浏览器：
		if (agent.contains("MSIE") || agent.contains("Trident")) {
			downloadName = java.net.URLEncoder.encode(downloadName, "UTF-8");
		} else {
			// 非IE浏览器的处理：
			downloadName = new String(downloadName.getBytes("UTF-8"), "ISO-8859-1");
		}
		response.setHeader("Content-Disposition", "attachment;fileName=\"" + downloadName + "\"");

		// 设置压缩流：直接写入response，实现边压缩边下载
		ZipOutputStream zipos = null;

		zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
		zipos.setMethod(ZipOutputStream.DEFLATED); // 设置压缩方法

		// 循环将文件写入压缩流
		DataOutputStream os = null;
		try {
			// 添加ZipEntry，并ZipEntry中写入文件流
			os = checkIsDirectory(filePath, zipos, os, null);
			zipos.closeEntry();
			return extracted();
		} catch (IOException e) {
			log.error("FileUtils zipDownload() have an IOException = {}", e);
			return extractedFalse();
		} finally {
			// 关闭流
			try {
				if (null != os) {
					os.flush();
					os.close();
				}
				if (null != zipos) {
					zipos.close();
				}
			} catch (IOException e) {
				log.error("FileUtils zipDownload() close resources have an IOException = {}", e);
			}
		}
	}
	
	
	/**
	 * 
	 * @param filePath
	 * @param zipos
	 * @param os
	 * @return
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private static DataOutputStream checkIsDirectory(File[] filePath, ZipOutputStream zipos, DataOutputStream os,
			String isDirectoryName) throws IOException, FileNotFoundException {
		for (int i = 0; i < filePath.length; i++) {
			if (!filePath[0].isFile()) {
				new FileNotFoundException();
				log.error("文件不存在");
			}
			if (filePath[i].isFile()) {
				String fileName = filePath[i].getName();
				if (StringUtil.isNotEmpty(isDirectoryName)) {
					fileName = isDirectoryName + "/" + fileName;
				}
				zipos.putNextEntry(new ZipEntry(fileName));
				os = new DataOutputStream(zipos);
				InputStream is = new FileInputStream(filePath[i]);
				byte[] b = new byte[BUFF_SIZE];
				int length = 0;
				while ((length = is.read(b)) != -1) {
					os.write(b, 0, length);
				}
				is.close();
			}
			if (filePath[i].isDirectory()) { // 如果是文件夹类型
				File[] files = filePath[i].listFiles();
				checkIsDirectory(files, zipos, os, filePath[i].getName());
			}
		}
		return os;
	}
	
	/**
	 * @Title: FileUtils
	 * @Description: TODO
	 * @author TimBrian
	 * @since 2021年11月8日 上午11:07:47
	 * @param request
	 * @param response
	 * @param downloadFileName 下载保存时文件的命名
	 * @param fileList 
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static boolean zipDownload(HttpServletRequest request, HttpServletResponse response, String downloadFileName, 
			List<FileUtilsVo> fileList) throws FileNotFoundException, IOException {
		// 响应头的设置
		response.reset();
		response.setCharacterEncoding("utf-8");
		response.setContentType("multipart/form-data");
		// 设置压缩包的名字
		// 解决不同浏览器压缩包名字含有中文时乱码的问题
		String downloadName = downloadFileName + ".zip";
		// 设置文件保存路径和文件名

		// 返回客户端浏览器的版本号、类型
		String agent = request.getHeader("USER-AGENT");
		// 针对IE或者以IE为内核的浏览器：
		if (agent.contains("MSIE") || agent.contains("Trident")) {
			downloadName = java.net.URLEncoder.encode(downloadName, "UTF-8");
		} else {
			// 非IE浏览器的处理：
			downloadName = new String(downloadName.getBytes("UTF-8"), "ISO-8859-1");
		}
		response.setHeader("Content-Disposition", "attachment;fileName=\"" + downloadName + "\"");

		// 设置压缩流：直接写入response，实现边压缩边下载
		ZipOutputStream zipos = null;

		zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
		zipos.setMethod(ZipOutputStream.DEFLATED); // 设置压缩方法

		// 循环将文件写入压缩流
		DataOutputStream os = null;
		try {
			// 添加ZipEntry，并ZipEntry中写入文件流
			os = checkIsDirectory(fileList, zipos, os);
			zipos.closeEntry();
			return extracted();
		} catch (IOException e) {
			log.error("FileUtils zipDownload() have an IOException = {}", e);
			return extractedFalse();
		} finally {
			// 关闭流
			try {
				if (null != os) {
					os.flush();
					os.close();
				}
				if (null != zipos) {
					zipos.close();
				}
			} catch (IOException e) {
				log.error("FileUtils zipDownload() close resources have an IOException = {}", e);
			}
		}
	}
	
	private static DataOutputStream checkIsDirectory(List<FileUtilsVo> fileList, ZipOutputStream zipos, DataOutputStream os) throws IOException, FileNotFoundException {
		InputStream fis = null;
		String fileName = null;
		for (FileUtilsVo fileUtilsVo : fileList) {
			fis = new ByteArrayInputStream(fileUtilsVo.getFileContent().getBytes());
			if (!StringUtils.isEmpty(fileUtilsVo.getFileExtension())) {
				fileName = fileUtilsVo.getFileName() + "." + fileUtilsVo.getFileExtension();
			}else {
				fileName = fileUtilsVo.getFileName();
			}
			zipos.putNextEntry(new ZipEntry(fileName));
			os = new DataOutputStream(zipos);
			byte[] b = new byte[BUFF_SIZE];
			int length = 0;
			while ((length = fis.read(b)) != -1) {
				os.write(b, 0, length);
			}
		}
		fis.close();
		return os;
	}
	
	/**
	 * 
	 * @Description: 释放资源
	 * @author: TimBrian
	 * @date: 2018年2月13日 上午10:28:07
	 */
	public static void close() {
		try {
			if (fileInputStream != null) {
				fileInputStream.close();
			}
			if (zipOutputStream != null) {
				zipOutputStream.close();
			}
		} catch (IOException e) {

			log.error("FileUtils close() have a IOException,IOException={}", e);
		}
	}
	
	/**
	 * 
	 * @Description: 删除文件
	 * @author: sledgewang
	 * @date: 2018年3月6日 下午12:24:01
	 * @param file
	 * @return
	 */
	public static boolean fileDelete(File file) {
		if (file.exists()) {
			if (file.isFile())
				return deleteFile(file);
			else
				return deleteDirectory(file);
		}
		return extractedFalse();
	}

	private static boolean deleteDirectory(File file) {
		File files[] = file.listFiles();
		boolean flag = false;
		for (int i = 0; i < files.length; i++) {
			if (files[i].isFile()) { // 删除子文件
				flag = deleteFile(files[i]);
				if (!flag) {
					break;
				}
			} else if (files[i].isDirectory()) {// 删除子目录
				flag = deleteDirectory(files[i]);
				files[i].delete();// 删除空的文件夹
				if (!flag) {
					break;
				}
			}
		}
		file.delete();// 删除根目录
		return flag;
	}

	private static boolean deleteFile(File file) {
		if (file.delete()) {
			return extracted();
		}
		return extractedFalse();
	}
	
	/**
	 * @Description: 单个文件下载
	 * @author: TimBrian
	 * @date: 2018年2月7日 下午4:22:32
	 * @param path
	 * @param fileName
	 * @param httpServletResponse
	 * @param servletContext
	 * @return
	 * @throws CollectMessageException
	 * @throws GlobalException
	 */
	public static boolean fileDownload(String path, String fileName, HttpServletResponse httpServletResponse, ServletContext servletContext) {
		File file = new File(path, fileName);
		try (FileInputStream fis = new FileInputStream(file);
				OutputStream fos = httpServletResponse.getOutputStream();) {

			String mimeType = servletContext.getMimeType(file.getAbsolutePath());
			if (mimeType == null) {
				mimeType = "application/octet-stream";
			}
			httpServletResponse.setContentType(mimeType);
			httpServletResponse.setContentLength((int) file.length());
			String headerkey = "Content-Disposition";
			String headerValue = String.format("attachment;filename=\"%s\"", file.getName());
			httpServletResponse.setHeader(headerkey, headerValue);

			byte[] buff = new byte[BUFF_SIZE];
			int flag = -1;
			while ((flag = fis.read(buff)) != -1) {
				fos.write(buff, 0, flag);
			}
			return extracted();
		} catch (FileNotFoundException e) {
			log.error("FileUtils fileDownload() have a FileNotFoundException,FileNotFoundException={}", e);
		} catch (IOException e) {
			log.error("FileUtils fileDownload() have a IOException,IOException={}", e);
		}
		return extractedFalse();
	}


	private static boolean extractedFalse() {
		return false;
	}
	
	/**
	 * @Title: FileUtils
	 * @Description: TODO
	 * @author TimBrian
	 * @since 2021年11月30日 下午8:20:30
	 * @param file
	 * @param fileName
	 * @param bytes
	 * @param response
	 * @return
	 */
	public static boolean fileDownload1(File file, String fileName, byte[] bytes, HttpServletResponse response) {
		if (!file.exists()) {
			file.mkdirs();
		}
		try(InputStream fis =  new ByteArrayInputStream(bytes);
				FileOutputStream fos = new FileOutputStream(new File(file, fileName));) {
			byte[] b = new byte[BUFF_SIZE];
			int length = 0;
			while ((length = fis.read(b)) != -1) {
				fos.write(b, 0, length);
			}
			return extracted();
		} catch (FileNotFoundException e) {
			log.error("FileUtils fileDownload() have a FileNotFoundException,FileNotFoundException={}", e);
		} catch (IOException e) {
			log.error("FileUtils fileDownload() have a IOException,IOException={}", e);
		}
		return false;
	}


	private static boolean extracted() {
		return true;
	}
	
}